﻿using System.Collections.Generic;
using Global.Tool;
using Map.Data;
using UnityEngine;

namespace Map.Manager
{
    /// <summary>
    /// 地图管理类
    /// </summary>
    public class MapManager : UnitySceneSingleton<MapManager>
    {
        private List<MapNode> _nodeAll;
        private List<MapNode> _nodePool;
        private MapNode[,] _map;
        private Transform objectPoolParent;
        private Transform nodeParent;
        private MapPoint2D deviationPoint;
        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            _nodeAll = new List<MapNode>();
            _nodePool = new List<MapNode>();
            objectPoolParent = new GameObject().transform;
            objectPoolParent.name = "objectPool";
            objectPoolParent.parent = transform;
            nodeParent = new GameObject().transform;
            nodeParent.parent = transform;
            nodeParent.name = "nodeParent";
        }

        /// <summary>
        /// 回收地图节点
        /// </summary>
        /// <param name="node"></param>
        private void Despawn(MapNode node)
        {
            node.gameObject.SetActive(false);
            node.transform.parent = objectPoolParent;
            if (!_nodePool.Contains(node))
                _nodePool.Add(node);
        }

        /// <summary>
        /// 通过缓存池取地图节点
        /// </summary>
        /// <returns></returns>
        private MapNode GetMapNodeAtPool()
        {
            MapNode node;
            if (_nodePool.Count > 0)
            {
                node = _nodePool[0];
                _nodePool.RemoveAt(0);
            }
            else
            {
                var obj = Resources.Load<GameObject>("Maps/MapGrid");
                node = GameObject.Instantiate(obj).GetComponent<MapNode>();
                _nodeAll.Add(node);
            }
            node.gameObject.SetActive(true);
            node.transform.parent = nodeParent;
            return node;
        }

        /// <summary>
        /// 创建地图
        /// </summary>
        /// <param name="xNum">地图列数</param>
        /// <param name="yNum">地图行数</param>
        public void CreateMap(int xNum, int yNum)
        {
            deviationPoint = new MapPoint2D(-xNum/2, -yNum/2);
            _nodePool.Clear();
            foreach (var node in _nodeAll)
            {
                Despawn(node);
            }
            _map = new MapNode[xNum, yNum];
            for (int x = 0; x < xNum; ++x)
            {
                for (int y = 0; y < yNum; ++y)
                {
                    var ix = x + deviationPoint.X;
                    var iy = y + deviationPoint.Y;
                    _map[x, y] = GetMapNodeAtPool();
                    _map[x, y].Init(ix,iy );
                    _map[x, y].transform.localPosition = new Vector3(Mathf.Abs(iy % 2) > 0 ? (ix * 3 + 1.5f) : ix * 3, 0, iy * 2.6f);
                    _map[x, y].name = "MapNode "+_map[x, y].GridPosition.ToString();
                }
            }
        }

        /// <summary>
        /// 通过MapPoint3D转到地图节点实例
        /// </summary>
        public MapNode this[MapPoint3D point3D]
        {
            get
            {
                var index2D = MapPoint3D.MapPoint3DAtIndex2D(point3D);
                return this[index2D];
            }
        }
    /// <summary>
        /// 通过MapPoint3D转到地图节点实例
        /// </summary>
        public MapNode this[int x, int y, int z]
        {
            get
            {
                var index2D = MapPoint3D.MapPoint3DAtIndex2D(x,y,z);
                return this[index2D];
            }
        }
        /// <summary>
        /// 通过索引转到地图节点实例
        /// </summary>
        public MapNode this[MapPoint2D index2D]
        {
            get { return this[index2D.X, index2D.Y]; }
        }
        /// <summary>
        /// 通过索引转到地图节点实例
        /// </summary>
        public MapNode this[int x, int y]
        {
            get
            {
                x -= deviationPoint.X;
                y -= deviationPoint.Y;
                var ix = (x > _map.GetLength(0) - 1) ? (_map.GetLength(0) - 1) : ((x < 0) ? 0 : x);
                var iy = (y > _map.GetLength(1) - 1) ? (_map.GetLength(1) - 1) : ((y < 0) ? 0 : y);
                return _map[ix, iy];
            }
        }

        public void Reset()
        {
            
        }
        // Use this for initialization

        void Start()
        {
            Init();
            CreateMap(50, 50);
        }
        // Update is called once per frame
        void Update()
        {

        }
    }
}
